import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

public class Tetris implements ActionListener {
    private static final int BOARD_WIDTH = 10;
    private static final int BOARD_HEIGHT = 20;
    private Board board;
    private Tetromino currentTetromino;
    private Timer timer;
    private TetrisPanel tetrisPanel;

    public Tetris() {
        board = new Board(BOARD_WIDTH, BOARD_HEIGHT);
    }

    public void gameLoop() {
        // 创建JFrame
        JFrame frame = new JFrame("Tetris");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(BOARD_WIDTH * 30, BOARD_HEIGHT * 30);

        // 创建TetrisPanel
        tetrisPanel = new TetrisPanel(this);
        frame.add(tetrisPanel);

        currentTetromino = Tetromino.createLTetromino(BOARD_WIDTH / 2 - 1,0);
        // 生成初始方块
        timer = new Timer(500, this);
        timer.start();

        // 添加键盘监听器
        frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                handleInput(e.getKeyCode());
            }
        });

        frame.setVisible(true);
    }

    private void handleInput(int keyCode) {
        switch (keyCode) {
            case KeyEvent.VK_LEFT:
                moveCurrentTetromino(-1, 0);
                break;
            case KeyEvent.VK_RIGHT:
                moveCurrentTetromino(1, 0);
                break;
            case KeyEvent.VK_UP:
                rotateCurrentTetromino();
                break;
            case KeyEvent.VK_DOWN:
                updateGameState();
                break;
        }
    }

    private void rotateCurrentTetromino() {
        Tetromino rotatedTetromino = new Tetromino(currentTetromino.getShape(), currentTetromino.getX(), currentTetromino.getY());
        rotatedTetromino.rotate();

        if (!board.checkCollision(rotatedTetromino.getShape(), rotatedTetromino.getX(), rotatedTetromino.getY())) {
            currentTetromino.rotate();
            tetrisPanel.repaint();
        }
    }

    private boolean moveCurrentTetromino(int dx, int dy) {
        int newX = currentTetromino.getX() + dx;
        int newY = currentTetromino.getY() + dy;

        if (!board.checkCollision(currentTetromino.getShape(), newX, newY)) {
            currentTetromino.setX(newX);
            currentTetromino.setY(newY);
            tetrisPanel.repaint();
            return true;
        }
        return false;
    }

    private void updateGameState() {
        if (!moveCurrentTetromino(0, 1)) {
            addToBoard(currentTetromino);
            board.clearFullRows();
            spawnNewTetromino();
        }
        tetrisPanel.repaint();
    }

    private void addToBoard(Tetromino tetromino) {
        int[][] shape = tetromino.getShape();
        int x = tetromino.getX();
        int y = tetromino.getY();

        for (int row = 0; row < shape.length; row++) {
            for (int col = 0; col < shape[row].length; col++) {
                if (shape[row][col] != 0) {
                    board.setCell(x + col, y + row, 1);
                }
            }
        }
    }

    private void spawnNewTetromino() {
        int randomShape = new Random().nextInt(7);

        switch (randomShape) {
            case 0:
                currentTetromino = Tetromino.createITetromino(0,0);
                break;
            case 1:
                currentTetromino = Tetromino.createOTetromino(0,0);
                break;
            case 2:
                currentTetromino = Tetromino.createTTetromino(0,0);
                break;
            case 3:
                currentTetromino = Tetromino.createSTetromino(0,0);
                break;
            case 4:
                currentTetromino = Tetromino.createZTetromino(0,0);
                break;
            case 5:
                currentTetromino = Tetromino.createJTetromino(0,0);
                break;
            case 6:
                currentTetromino = Tetromino.createLTetromino(0,0);
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + randomShape);
        }
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        updateGameState();
        if (board.isGameOver()) {
            timer.stop();
            JOptionPane.showMessageDialog(null, "游戏结束!", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    public static void main(String[] args) {
        Tetris tetris = new Tetris();
        tetris.gameLoop();
    }

    public Tetromino getCurrentTetromino() {
        return this.currentTetromino;
    }

    public Board getBoard() {
        return this.board;
    }

    public int getScore() {
        return board.getScore();
    }
}
